'use client';

import useToast from '@/hooks/useToast';
import {
  type Dispatch,
  type SetStateAction,
  useEffect,
  useImperativeHandle,
  useRef,
  useState,
} from 'react';
import type {
  ICreateEditPostDraftBody,
  ICreateNewPostDraftBody,
  IUploadMessageSendFile,
  IUploadMessageSendFileBody,
  IUploadPostContent,
  IUploadPostContentBody,
  IUploadPostNewFile,
  IUploadPostNewFileBody,
  IUploadPostTemplateFile,
  IUploadPostTemplateFileBody,
} from '@/interfaces';
import { useMutation } from '@tanstack/react-query';
import type { TBody, TMetadata } from '@/types';
import {
  createEditPostDraft,
  createNewPostDraft,
  uploadMessageSendFile,
  uploadPostContent,
  uploadPostNewFile,
  uploadPostTemplateFile,
} from '@/services/api';
import {
  getEditorContentHtml,
  initEditor,
  setEditorContentHtml,
} from '@/lib/editor';
import YwBox from '@/app/[locale]/file/ywbox';
import Script from 'next/script';
import classNames from 'classnames';
import { flushSync } from 'react-dom';
import { restoreInitialData } from '@/lib/editor/restore';
import { useTranslations } from 'use-intl';

export default function EditorDynamic({
  editorBoxClasss = '',
  id,
  initialData = '',
  metadata,
  placeholder = '请输入内容',
  extraData,
  type,
  currentEditorRef,
  setIsSaving,
}: {
  editorBoxClasss?: string;
  id?: string | number;
  initialData?: string;
  isEdit?: boolean;
  metadata: TMetadata;
  extraData?: any;
  placeholder?: string;
  type: 'message' | 'newPost' | 'editPost' | 'postTemplate' | 'section';
  currentEditorRef: any;
  setIsSaving?: Dispatch<SetStateAction<boolean>>;
}) {
  const env = metadata.env;
  const { show } = useToast();
  const editorRef = useRef<any>(null);
  const editorElementRef = useRef<HTMLDivElement>(null);
  const ywboxRef = useRef<{
    open: Function;
  }>(null);
  const [isLoading, setIsLoading] = useState(true);
  const t = useTranslations('PostEditPage');

  useImperativeHandle(currentEditorRef, () => ({
    getEditorContent,
    setEditorContent,
  }));

  useEffect(() => {
    if (!isLoading && initialData) {
      editorRef.current.editor.setData(
        initialData ? restoreInitialData(initialData) : '',
      );
    }
  }, [isLoading, initialData]);

  const uploadPostTemplateFileMutation = useMutation(
    async (variables: TBody<IUploadPostTemplateFileBody>) => {
      return (await uploadPostTemplateFile(
        variables,
      )) as IUploadPostTemplateFile;
    },
  );
  const uploadMessageSendFileMutation = useMutation(
    async (variables: TBody<IUploadMessageSendFileBody>) => {
      return (await uploadMessageSendFile(variables)) as IUploadMessageSendFile;
    },
  );
  const uploadPostContentMutation = useMutation(
    async (variables: TBody<IUploadPostContentBody>) => {
      return (await uploadPostContent(variables)) as IUploadPostContent;
    },
  );
  const uploadPostNewContentMutation = useMutation(
    async (variables: TBody<IUploadPostNewFileBody>) => {
      return (await uploadPostNewFile(variables)) as IUploadPostNewFile;
    },
  );
  const createNewPostDraftMutation = useMutation(
    async (variables: TBody<ICreateNewPostDraftBody>) => {
      await createNewPostDraft(variables);
    },
  );
  const createEditPostDraftMutation = useMutation(
    async (variables: TBody<ICreateEditPostDraftBody>) => {
      await createEditPostDraft(variables);
    },
  );

  function getEditorContent() {
    const current = editorRef.current;
    if (!current) {
      show({
        type: 'DANGER',
        message: t('editorNotFound'),
      });
    }
    return getEditorContentHtml(current.editor);
  }

  function setEditorContent(content: string = '') {
    const current = editorRef.current;
    if (!current) {
      show({
        type: 'DANGER',
        message: t('editorNotFound'),
      });
    }
    setEditorContentHtml(current.editor, content);
  }

  function onReady() {
    const element = editorElementRef.current;
    if (!element) {
      show({
        type: 'DANGER',
        message: t('editorNotFound'),
      });
      return;
    }

    editorRef.current = initEditor({
      element: element,
      config: {
        initialData: initialData ? restoreInitialData(initialData) : '',
        placeholder,
        ywFileUpload: {
          upload: async (file: File) => {
            try {
              let result;
              if (type === 'postTemplate') {
                if (!id) {
                  show({
                    type: 'DANGER',
                    message: t('boardDataNotFound'),
                  });
                  return Promise.reject(new Error(t('boardDataNotFound')));
                }

                result = await uploadPostTemplateFileMutation.mutateAsync({
                  id,
                  data: {
                    file,
                  },
                });
              } else if (type === 'message') {
                result = await uploadMessageSendFileMutation.mutateAsync({
                  data: {
                    file,
                  },
                });
              } else if (type === 'editPost') {
                result = await uploadPostContentMutation.mutateAsync({
                  id: id + '',
                  data: {
                    file,
                  },
                });
              } else if (type === 'newPost') {
                result = await uploadPostNewContentMutation.mutateAsync({
                  data: {
                    file,
                  },
                });
              } else {
                show({
                  type: 'DANGER',
                  message: t('uploadTypeNotFound'),
                });
                return Promise.reject(new Error(t('uploadTypeNotFound')));
              }

              result.urls.default = env.APP_OSS_SERVER + result.urls.default;
              return result.urls;
            } catch (e) {
              if (type === 'postTemplate') {
                uploadPostTemplateFileMutation.reset();
              } else if (type === 'message') {
                uploadMessageSendFileMutation.reset();
              } else if (type === 'editPost') {
                uploadPostContentMutation.reset();
              } else if (type === 'newPost') {
                uploadPostNewContentMutation.reset();
              }

              show({
                type: 'DANGER',
                message: e,
              });
              throw e;
            }
          },
          abort: () => {},
        },
        ywFileBox: {
          onOpen: (options: { onClose: () => void; onSelect: () => void }) => {
            if (!ywboxRef.current) {
              show({
                type: 'DANGER',
                message: t('failedToOpenFileManager'),
              });
              return;
            }

            ywboxRef.current.open(options);
          },
        },
        autosave: {
          waitingTime: 5000,
          save: async () => {
            try {
              if (type === 'editPost' || type === 'newPost') {
                await flushSync(async () => {
                  if (type === 'editPost') {
                    await createEditPostDraftMutation.mutateAsync({
                      id: id + '',
                      data: {
                        name: extraData.postName,
                        overview: extraData.postOverview,
                        content: getEditorContent(),
                      },
                    });
                  } else if (type === 'newPost') {
                    await createNewPostDraftMutation.mutateAsync({
                      data: {
                        name: extraData.postName,
                        overview: extraData.postOverview,
                        content: getEditorContent(),
                      },
                    });
                  }
                });

                show({
                  type: 'PRIMARY',
                  message: t('autoSaveDraftCompleted'),
                });
              }
            } catch (e) {
              if (type === 'editPost' || type === 'newPost') {
                if (type === 'editPost') {
                  createEditPostDraftMutation.reset();
                } else if (type === 'newPost') {
                  createNewPostDraftMutation.reset();
                }
                show({
                  type: 'WARNING',
                  message: t('autoSaveDraftFailed'),
                });
              }

              show({
                type: 'DANGER',
                message: e,
              });
            }
          },
        },
        setIsSaving,
      },
    });

    setIsLoading(false);
  }

  function onError(e: any) {
    show({
      type: 'DANGER',
      message: e,
    });
  }

  return (
    <>
      <div className={classNames(editorBoxClasss)}>
        <div ref={editorElementRef}></div>
        <YwBox ref={ywboxRef} id={id} type={type} oss={env.APP_OSS_SERVER} />
      </div>

      <Script src="/lib/ckeditor.min.js" onReady={onReady} onError={onError} />
    </>
  );
}
